import requests
import re
import json
from jsonpath_ng import parse


class RequestExecutor:
    def __init__(self, context):
        """初始化请求执行器
        Args:
            context: 上下文变量存储字典
            #base_url: 基础API地址
        """
        self.context = context  # 存储提取的变量(token等)
        #self.base_url = base_url  # 基础URL
        self.results = []  # 存储所有测试结果

    def execute_request(self, request_config):
        """执行单个接口请求
        Args:
            request_config: 加载接口请求参数
        Returns:
            包含请求和响应信息的字典
        """
        try:
            # 准备请求参数
            method = request_config["method"].upper()
            # url = self.base_url + request_config["url"]
            url = request_config["url"]
            headers = self._replace_vars(request_config.get("headers", {}))
            data = self._prepare_data(request_config.get("data", {}))
            params = self._prepare_params(method, data)
            # 发送HTTP请求
            response = requests.request(
                method=method,
                url=url,
                headers=headers,
                params=params,
                json=data if method != "GET" else None,
                timeout=10
            )

            # 处理响应
            self._handle_extractors(response, request_config.get("extract", {}))
            assertions = self._check_assertions(response, request_config.get("assertions", []))

            # 构建结果字典
            result = {
                "name": request_config["name"],  # 测试名称
                "url": url,  # 完整URL
                "method": method,  # HTTP方法
                "status": response.status_code,  # 状态码
                "request": {"headers": headers, "body": data},  # 请求信息
                "response": {"headers": dict(response.headers), "body": response.text},  # 响应信息
                "assertions": assertions,  # 断言结果列表
                "success": all(a["success"] for a in assertions)  # 是否全部断言成功
            }

        except Exception as e:
            result = self._create_error_result(request_config, str(e))

        self.results.append(result)
        return result

    def _replace_vars(self, data):
        """替换变量占位符（如${token}）
        Args:
            data: 可能包含占位符的数据
        Returns:
            替换后的数据
        """
        if isinstance(data, dict):
            return {k: self._replace_vars(v) for k, v in data.items()}
        if isinstance(data, str):
            return re.sub(r'\$\{(.+?)\}', lambda m: str(self.context.get(m.group(1), "")), data)
        return data

    def _prepare_data(self, data):
        """准备请求数据（处理变量替换）
        Args:
            data: 原始请求数据
        Returns:
            处理后的请求数据
        """
        if data == "": return {}
        return self._replace_vars(data)

    def _prepare_params(self, method, data):
        """为GET请求准备查询参数
        Args:
            method: HTTP方法
            data: 请求数据
        Returns:
            GET请求返回参数字典，其他方法返回None
        """
        return data if method == "GET" else None

    def _handle_extractors(self, response, extractors):
        """处理响应提取器
        Args:
            response: 响应对象
            extractors: 提取器配置字典
        """
        try:
            json_data = response.json()
            for key, expr in extractors.items():
                matches = parse(expr).find(json_data)
                if matches:
                    self.context[key] = matches[0].value
        except:
            pass

    def _check_assertions(self, response, assertions):
        """全动态断言处理器"""
        results = []
        try:
            resp_data = response.json() if response.content else None
        except json.JSONDecodeError:
            resp_data = None

        for assertion in assertions:
            result = {
                "type": assertion["type"],
                "description": assertion.get("description", ""),
                "success": False,
                "expected": assertion.get("expected"),
                "actual": None
            }

            try:
                # 动态生成处理器方法名
                handler_name = f"_handle_{assertion['type']}"
                handler = getattr(self, handler_name, None)

                if not handler:
                    raise AttributeError(f"没有对应的断言处理器: {assertion['type']}")

                # 执行断言处理
                handler_result = handler(response, assertion, resp_data)
                result.update(handler_result)

            except Exception as e:
                result["error"] = f"断言处理失败: {str(e)}"

            results.append(result)
        return results

    # 内置处理器 --------------------------------------------------

    def _handle_status_code(self, response, assertion, _):
        return {
            "actual": response.status_code,
            "success": response.status_code == assertion["expected"]
        }
    def _handle_code(self, _, assertion, resp_data):
        """动态处理业务code断言（使用JSON Path）"""
        if not resp_data:
            raise ValueError("响应不是有效JSON")

        matches = parse(assertion["expression"]).find(resp_data)
        if not matches:
            return {
                "actual": None,
                "error": f"JSON路径未找到: {assertion['expression']}",
                "success": False
            }

        actual = matches[0].value
        return {
            "actual": actual,
            "success": str(actual) == str(assertion["expected"])
        }

    def _handle_response_time(self, response, assertion, _):
        """响应时间断言"""
        actual_ms = response.elapsed.total_seconds() * 1000
        return {
            "expected": f"<={assertion['max_ms']}ms",
            "actual": f"{actual_ms:.2f}ms",
            "success": actual_ms <= assertion["max_ms"]
        }

    def _handle_contains(self, response, assertion, _):
        """文本包含断言"""
        return {
            "actual": "Response Text",
            "success": assertion["text"] in response.text
        }

    def _handle_json_path(self, _, assertion, resp_data):
        """通用JSON Path处理器"""
        if not resp_data:
            raise ValueError("响应不是有效JSON")

        jsonpath_expr = parse(assertion["expression"])
        matches = jsonpath_expr.find(resp_data)

        if not matches:
            return {
                "expected": assertion["expected"],
                "actual": None,
                "error": f"路径未匹配: {assertion['expression']}",
                "success": False
            }

        actual = matches[0].value
        return {
            "expected": assertion["expected"],
            "actual": actual,
            "success": str(actual) == str(assertion["expected"])
        }


    def _create_error_result(self, config, error):
        """创建错误结果
        Args:
            config: 请求配置
            error: 错误信息
        Returns:
            错误结果字典
        """
        return {
            "name": config.get("name", ""),
            "url": config.get("url", ""),
            "method": config.get("method", ""),
            "status": None,
            "request": {"headers": config.get("headers", {}), "body": config.get("data", {})},
            "response": None,
            "assertions": [],
            "success": False,
            "error": error
        }